home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-27 | 14.6 KB | 350 lines | [TEXT/ROSA] |
- Common Lisp the Language, 2nd Edition
- -------------------------------------------------------------------------------
-
- 16. Hash Tables
-
- A hash table is a Lisp object that can efficiently map a given Lisp object to
- another Lisp object. Each hash table has a set of entries, each of which
- associates a particular key with a particular value. The basic functions that
- deal with hash tables can create entries, delete entries, and find the value
- that is associated with a given key. Finding the value is very fast, even if
- there are many entries, because hashing is used; this is an important advantage
- of hash tables over property lists.
-
- A given hash table can associate only one value with a given key; if you try to
- add a second value, it will replace the first. Also, adding a value to a hash
- table is a destructive operation; the hash table is modified. By contrast,
- association lists can be augmented non-destructively.
-
- Hash tables come in three kinds, the difference being whether the keys are
- compared with eq, eql, or equal. In other words, there are hash tables that
- hash on Lisp objects (using eq or eql) and there are hash tables that hash on
- tree structure (using equal).
-
- Hash tables are created with the function make-hash-table, which takes various
- options, including which kind of hash table to make (the default being the eql
- kind). To look up a key and find the associated value, use gethash. New entries
- are added to hash tables using setf with gethash. To remove an entry, use
- remhash. Here is a simple example.
-
- (setq a (make-hash-table))
- (setf (gethash 'color a) 'brown)
- (setf (gethash 'name a) 'fred)
- (gethash 'color a) => brown
- (gethash 'name a) => fred
- (gethash 'pointy a) => nil
-
- In this example, the symbols color and name are being used as keys, and the
- symbols brown and fred are being used as the associated values. The hash table
- has two items in it, one of which associates from color to brown, and the other
- of which associates from name to fred.
-
- Keys do not have to be symbols; they can be any Lisp object. Similarly, values
- can be any Lisp object.
-
- [old_change_begin]
- When a hash table is first created, it has a size, which is the maximum number
- of entries it can hold. Usually the actual capacity of the table is somewhat
- less, since the hashing is not perfectly collision-free. With the maximum
- possible bad luck, the capacity could be very much less, but this rarely
- happens. If so many entries are added that the capacity is exceeded, the hash
- table will automatically grow, and the entries will be rehashed (new hash
- values will be recomputed, and everything will be rearranged so that the fast
- hash lookup still works). This is transparent to the caller; it all happens
- automatically.
- [old_change_end]
-
- [change_begin]
- There is a discrepancy between the preceding description of the size of a hash
- table and the description of the :size argument in the specification below of
- make-hash-table.
-
- X3J13 voted in June 1989 (HASH-TABLE-SIZE) to regard the latter description
- as definitive: the :size argument is approximately the number of entries that
- can be inserted without having to enlarge the hash table. This definition is
- certainly more convenient for the user.
- [change_end]
-
- -------------------------------------------------------------------------------
- Compatibility note: This hash table facility is compatible with Lisp Machine
- Lisp. It is similar to the hasharray facility of Interlisp, and some of the
- function names are the same. However, it is not compatible with Interlisp. The
- exact details and the order of arguments are designed to be consistent with the
- rest of MacLisp rather than with Interlisp. For instance, the order of
- arguments to maphash is different, there is no ``system hash table,'' and there
- is not the Interlisp restriction that keys and values may not be nil.
- -------------------------------------------------------------------------------
-
- -------------------------------------------------------------------------------
-
- * Hash Table Functions
- * Primitive Hash Function
-
- -------------------------------------------------------------------------------
-
- 16.1. Hash Table Functions
-
- This section documents the functions for hash tables, which use objects as keys
- and associate other objects with them.
-
- [Function]
- make-hash-table &key :test :size :rehash-size :rehash-threshold
-
- This function creates and returns a new hash table. The :test argument
- determines how keys are compared; it must be one of the three values #'eq,
- #'eql, or #'equal, or one of the three symbols eq, eql, or equal. If no test is
- specified, eql is assumed.
-
- [change_begin]
- X3J13 voted in January 1989 (HASH-TABLE-TESTS) to add a fourth type of hash
- table: the value of #'equalp and the symbol equalp are to be additional valid
- possibilities for the :test argument.
-
- Note that one consequence of the vote to change the rules of floating-point
- contagion (CONTAGION-ON-NUMERICAL-COMPARISONS) (described in section 12.1) is
- to require =, and therefore also equalp, to compare the values of numbers
- exactly and not approximately, making equalp a true equivalence relation on
- numbers.
-
- Another valuable use of equalp hash tables is case-insensitive comparison of
- keys that are strings.
- [change_end]
-
- The :size argument sets the initial size of the hash table, in entries. (The
- actual size may be rounded up from the size you specify to the next ``good''
- size, for example to make it a prime number.) You won't necessarily be able to
- store precisely this many entries into the table before it overflows and
- becomes bigger, but this argument does serve as a hint to the implementation of
- approximately how many entries you intend to store.
-
- [change_begin]
- X3J13 voted in January 1989 (ARGUMENTS-UNDERSPECIFIED) to clarify that the
- :size argument must be a non-negative integer.
-
- X3J13 voted in June 1989 (HASH-TABLE-SIZE) to regard the preceding
- description of the :size argument as definitive: it is approximately the number
- of entries that can be inserted without having to enlarge the hash table.
- [change_end]
-
- The :rehash-size argument specifies how much to increase the size of the hash
- table when it becomes full. This can be an integer greater than zero, which is
- the number of entries to add, or it can be a floating-point number greater than
- 1, which is the ratio of the new size to the old size. The default value for
- this argument is implementation-dependent.
-
- [old_change_begin]
- The :rehash-threshold argument specifies how full the hash table can get before
- it must grow. This can be an integer greater than zero and less than the
- :rehash-size (in which case it will be scaled whenever the table is grown), or
- it can be a floating-point number between zero and 1. The default value for
- this argument is implementation-dependent.
- [old_change_end]
-
- [change_begin]
- X3J13 voted in June 1989 (HASH-TABLE-SIZE) to replace the preceding
- specification of the :rehash-threshold argument with the following: The
- :rehash-threshold argument specifies how full the hash table can get before it
- must grow. It may be any real number between 0 and 1, inclusive. It indicates
- the maximum desired level of hash table occupancy. An implementation is
- permitted to ignore this argument. The default value for this argument is
- implementation-dependent.
- [change_end]
-
- An example of the use of make-hash-table:
-
- (make-hash-table :rehash-size 1.5
- :size (* number-of-widgets 43))
-
- [Function]
- hash-table-p object
-
- hash-table-p is true if its argument is a hash table, and otherwise is false.
-
- (hash-table-p x) == (typep x 'hash-table)
-
- [Function]
- gethash key hash-table &optional default
-
- gethash finds the entry in hash-table whose key is key and returns the
- associated value. If there is no such entry, gethash returns default, which is
- nil if not specified.
-
- gethash actually returns two values, the second being a predicate value that is
- true if an entry was found, and false if no entry was found.
-
- setf may be used with gethash to make new entries in a hash table. If an entry
- with the specified key already exists, it is removed before the new entry is
- added. The default argument may be specified to gethash in this context; it is
- ignored by setf but may be useful in such macros as incf that are related to
- setf:
-
- (incf (gethash a-key table 0))
-
- means approximately the same as
-
- (setf (gethash a-key table 0)
- (+ (gethash a-key table 0) 1))
-
- which in turn would be treated as simply
-
- (setf (gethash a-key table)
- (+ (gethash a-key table 0) 1))
-
- [Function]
- remhash key hash-table
-
- remhash removes any entry for key in hash-table. This is a predicate that is
- true if there was an entry or false if there was not.
-
- [Function]
- maphash function hash-table
-
- For each entry in hash-table, maphash calls function on two arguments: the key
- of the entry and the value of the entry; maphash then returns nil. If entries
- are added to or deleted from the hash table while a maphash is in progress, the
- results are unpredictable, with one exception: if the function calls remhash to
- remove the entry currently being processed by the function, or performs a setf
- of gethash on that entry to change the associated value, then those operations
- will have the intended effect. For example:
-
- ;;; Alter every entry in MY-HASH-TABLE, replacing the value with
- ;;; its square root. Entries with negative values are removed.
- (maphash #'(lambda (key val)
- (if (minusp val)
- (remhash key my-hash-table)
- (setf (gethash key my-hash-table) (sqrt val))))
- my-hash-table)
-
- [change_begin]
- X3J13 voted in January 1989 (MAPPING-DESTRUCTIVE-INTERACTION) to restrict
- user side effects; see section 7.9.
- [change_end]
-
- [Function]
- clrhash hash-table
-
- This removes all the entries from hash-table and returns the hash table itself.
-
- [Function]
- hash-table-count hash-table
-
- This returns the number of entries in the hash-table. When a hash table is
- first created or has been cleared, the number of entries is zero.
-
- [change_begin]
-
- [Macro]
- with-hash-table-iterator (mname hash-table) {form}*
-
- X3J13 voted in January 1989 (HASH-TABLE-PACKAGE-GENERATORS) to add the macro
- with-hash-table-iterator.
-
- The name mname is bound and defined as if by macrolet, with the body forms as
- its lexical scope, to be a ``generator macro'' such that successive invocations
- (mname) will return entries, one by one, from the hash table that is the value
- of the expression hash-table (which is evaluated exactly once).
-
- At each invocation of the generator macro, there are two possibilities. If
- there is yet another unprocessed entry in the hash table, then three values are
- returned: t, the key of the hash table entry, and the associated value of the
- hash table entry. On the other hand, if there are no more unprocessed entries
- in the hash table, then one value is returned: nil.
-
- The implicit interior state of the iteration over the hash table entries has
- dynamic extent. While the name mname has lexical scope, it is an error to
- invoke the generator macro once the with-hash-table-iterator form has been
- exited.
-
- Invocations of with-hash-table-iterator and related macros may be nested, and
- the generator macro of an outer invocation may be called from within an inner
- invocation (assuming that its name is visible or otherwise made available).
-
- X3J13 voted in January 1989 (MAPPING-DESTRUCTIVE-INTERACTION) to restrict
- user side effects; see section 7.9.
-
- -------------------------------------------------------------------------------
- Rationale: This facility is a bit more flexible than maphash. It makes possible
- a portable and efficient implementation of loop clauses for iterating over hash
- tables (see chapter 26).
- -------------------------------------------------------------------------------
-
- (setq turtles (make-hash-table :size 9 :test 'eq))
- (setf (gethash 'howard-kaylan turtles) '(musician lead-singer))
- (setf (gethash 'john-barbata turtles) '(musician drummer))
- (setf (gethash 'leonardo turtles) '(ninja leader blue))
- (setf (gethash 'donatello turtles) '(ninja machines purple))
- (setf (gethash 'al-nichol turtles) '(musician guitarist))
- (setf (gethash 'mark-volman turtles) '(musician great-hair))
- (setf (gethash 'raphael turtles) '(ninja cool rude red))
- (setf (gethash 'michaelangelo turtles) '(ninja party-dude orange))
- (setf (gethash 'jim-pons turtles) '(musician bassist))
-
- (with-hash-table-iterator (get-turtle turtles)
- (labels ((try (got-one &optional key value)
- (when got-one ;Remember, keys may show up in any order
- (when (eq (first value) 'ninja)
- (format t "~%~:(~A~): ~{~A~^, ~}"
- key (rest value)))
- (multiple-value-call #'try (get-turtle)))))
- (multiple-value-call #'try (get-turtle)))) ;Prints 4 lines
- Michaelangelo: PARTY-DUDE, ORANGE
- Leonardo: LEADER, BLUE
- Raphael: COOL, RUDE, RED
- Donatello: MACHINES, PURPLE
- => nil
-
- [change_end]
-
- [change_begin]
-
- [Function]
- hash-table-rehash-size hash-table
- hash-table-rehash-threshold hash-table
- hash-table-size hash-table
- hash-table-test hash-table
-
- X3J13 voted in March 1989 (HASH-TABLE-ACCESS) to add four accessor functions
- that return values suitable for use in a call to make-hash-table in order to
- produce a new hash table with state corresponding to the current state of the
- argument hash table.
-
- hash-table-rehash-size returns the current rehash size of a hash table.
-
- hash-table-rehash-threshold returns the current rehash threshold.
-
- hash-table-size returns the current size of a hash table.
-
- hash-table-test returns the test used for comparing keys. If the test is one of
- the standard test functions, then the result will always be a symbol, even if
- the function itself was specified when the hash-table was created. For example:
-
- (hash-table-test (make-hash-table :test #'equal)) => equal
-
- Implementations that extend make-hash-table by providing additional
- possibilities for the :test argument may determine how the value returned by
- hash-table-test is related to such additional tests.
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 16.2. Primitive Hash Function
-
- The function sxhash is a convenient tool for the user who needs to create more
- complicated hashed data structures than are provided by hash-table objects.
-
- [Function]
- sxhash object
-
- sxhash computes a hash code for an object and returns the hash code as a
- non-negative fixnum. A property of sxhash is that (equal x y) implies (=
- (sxhash x) (sxhash y)).
-
- The manner in which the hash code is computed is implementation-dependent but
- independent of the particular ``incarnation'' or ``core image.'' Hash values
- produced by sxhash may be written out to files, for example, and meaningfully
- read in again into an instance of the same implementation.
-
- -------------------------------------------------------------------------------
-
-
-